/************************************************************************/
/*    Author: Scott Bevin                                               */
/************************************************************************/

#include "QuickAndDirtyOgreDebugRenderer.h"

#include "MathHelper.h"
#include "Utilities.h"

namespace XF
{
	int QuickAndDirtyOgreDebugRenderer::smNextId = 0;
	QuickAndDirtyOgreDebugRenderer* QuickAndDirtyOgreDebugRenderer::mSingletonInstance = NULL;

	QuickAndDirtyOgreDebugRenderer* QuickAndDirtyOgreDebugRenderer::GetInstance()
	{
		assert(mSingletonInstance);
		
		return mSingletonInstance;
	}

	void QuickAndDirtyOgreDebugRenderer::InitializeStaticVersion(XF::OgreRenderer *renderer)
	{
		assert(!mSingletonInstance);
		mSingletonInstance = new QuickAndDirtyOgreDebugRenderer(renderer);
	}

	void QuickAndDirtyOgreDebugRenderer::KillStaticVersion()
	{
		delete mSingletonInstance;
		mSingletonInstance = NULL;
	}

	QuickAndDirtyOgreDebugRenderer::QuickAndDirtyOgreDebugRenderer(XF::OgreRenderer *renderer)
	{
		mColourAllowdToChange = true;
		mId = ++smNextId;

		mRenderer = renderer;

		mNode = renderer->GetDefaultSceneManager()->getRootSceneNode()->createChildSceneNode("QuickAndDirtyOgreRendererNode" + XF::Utilities::ToString(mId));
		mManObj = renderer->GetDefaultSceneManager()->createManualObject("QuickAndDirtyOgreRendererManObj" + XF::Utilities::ToString(mId));
	
		mNode->attachObject(mManObj);	

		mMaterialString = "QuickAndDirtyOgreRendererMaterial" + XF::Utilities::ToString(mId);

		Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create(mMaterialString, "debugger");
		material->setReceiveShadows(false);
		material->getTechnique(0)->setLightingEnabled(false);

		mY = 0.0f;
	}

	QuickAndDirtyOgreDebugRenderer::~QuickAndDirtyOgreDebugRenderer()
	{
		//mRenderer->GetDefaultSceneManager()->getRootSceneNode()->removeAndDestroyChild("QuickAndDirtyOgreRendererNode" + XF::Utilities::ToString(mId));
	}

	void QuickAndDirtyOgreDebugRenderer::Clear()
	{
		mManObj->clear(); //chris
	}

	void QuickAndDirtyOgreDebugRenderer::Begin()
	{		
		mManObj->clear();
		mManObj->begin(mMaterialString, Ogre::RenderOperation::OT_LINE_LIST);
		
	}

	void QuickAndDirtyOgreDebugRenderer::End()
	{		
		mManObj->end();
	}

	void QuickAndDirtyOgreDebugRenderer::DrawLine( const XF::Vector3 &p1, const XF::Vector3 &p2 )
	{
		DrawLine( XF::Vector2(p1.x,p1.z), XF::Vector2(p2.x,p2.z) );
	}
	void QuickAndDirtyOgreDebugRenderer::DrawLine( const XF::Vector2 &p1, const XF::Vector2 &p2 )
	{
		mManObj->position(p1.x, mY, p1.y);
		mManObj->position(p2.x, mY, p2.y);
		mColourAllowdToChange = true;
	}

	void QuickAndDirtyOgreDebugRenderer::DrawLineStrip( std::vector<XF::Vector2> &lines )
	{
		if(lines.size() < 2) return;

		for(int i = 0; i < (int)lines.size() - 1; ++i)
		{
			mManObj->position(lines[i].x, mY, lines[i].y);
			mManObj->position(lines[i + 1].x, mY, lines[i + 1].y);
		}
		mColourAllowdToChange = true;
	}
	void QuickAndDirtyOgreDebugRenderer::DrawCircleFilled( const XF::Vector3 &center, float radius, int smoothFactor /*= 16*/ )
	{
		DrawCircleFilled( XF::Vector2(center.x,center.z),  radius,  smoothFactor );
	}
	void QuickAndDirtyOgreDebugRenderer::DrawCircle( const XF::Vector3 &center, float radius, int smoothFactor /*= 16*/ )
	{
		
		DrawCircle( XF::Vector2(center.x,center.z),  radius,  smoothFactor );
	}
	void QuickAndDirtyOgreDebugRenderer::SetFill(bool fill)
	{
		mManObj->end();
		if(fill)
		{			
			mManObj->begin(mMaterialString, Ogre::RenderOperation::OT_TRIANGLE_FAN);
		}
		else
		{
			mManObj->begin(mMaterialString, Ogre::RenderOperation::OT_LINE_LIST);
		}
	}
	void QuickAndDirtyOgreDebugRenderer::DrawCylinder( const XF::Vector3 &pos1,const XF::Vector3 &pos2 , float radius, int smoothFactor /*= 16*/ ) //chris
	{
		//smoothFactor = XF::MathHelper::Max(smoothFactor, 8);

		float angleChange = XF::MathHelper::TwoPi() / smoothFactor;
		float angle = 0.0f;

		for(int i = 0; i < smoothFactor; ++i)
		{
			mManObj->position(
				pos1.x + (cos(angle) * radius),
				pos1.y + (sin(angle) * radius),
				pos1.z + (cos(angle) * radius)
				);

			angle += angleChange;

	
			mManObj->position(
				pos2.x + (cos(angle) * radius),
				 
				pos2.y + (sin(angle) * radius),
				pos1.z + (cos(angle) * radius));

			
		}
		mColourAllowdToChange = true;
	}
	void QuickAndDirtyOgreDebugRenderer::DrawCircle( const XF::Vector2 &center, float radius, int smoothFactor /*= 16*/ )
	{
//		Ogre::ManualObject* obj;

		

		smoothFactor = XF::MathHelper::Max(smoothFactor, 8);

		float angleChange = XF::MathHelper::TwoPi() / smoothFactor;
		float angle = 0.0f;

		for(int i = 0; i < smoothFactor; ++i)
		{
			mManObj->position(
				center.x + (cos(angle) * radius),
				mY, 
				center.y + (sin(angle) * radius));

			mManObj->position(
				center.x + (cos(angle + angleChange) * radius),
				mY, 
				center.y + (sin(angle + angleChange) * radius));

			angle += angleChange;
		}
		mColourAllowdToChange = true;
	}

	void QuickAndDirtyOgreDebugRenderer::DrawRect( float x1, float x2, float y1, float y2 )
	{
		mManObj->position(x1, mY, y1);
		mManObj->position(x2, mY, y1);

		mManObj->position(x2, mY, y1);
		mManObj->position(x2, mY, y2);

		mManObj->position(x2, mY, y2);
		mManObj->position(x1, mY, y2);

		mManObj->position(x1, mY, y2);
		mManObj->position(x1, mY, y1);
		mColourAllowdToChange = true;
	}

	void QuickAndDirtyOgreDebugRenderer::Color( float r, float g, float b, float a /*= 1.0f*/ )
	{
		if(mColourAllowdToChange)
		{
			mColourAllowdToChange = false;
			mColor = Ogre::Vector4(r, g, b, a);
			mManObj->colour(mColor.x, mColor.y,mColor.z, mColor.w);
		}
		
		//mUnfilledManObj->colour(mColor.x, mColor.y, mColor.z, mColor.w);
		//mFilledManObj->colour(mColor.x, mColor.y, mColor.z, mColor.w);
	}

	void QuickAndDirtyOgreDebugRenderer::DrawCircleFilled( const XF::Vector2 &center, float radius, int smoothFactor /*= 16*/ )
	{
		smoothFactor = XF::MathHelper::Max(smoothFactor, 8);

		float angleChange = XF::MathHelper::TwoPi() / smoothFactor;
		float angle = 0.0f;
		
		//mManObj->begin(mMaterialString, Ogre::RenderOperation::OT_TRIANGLE_FAN);
		//mManObj->colour(mColor.x, mColor.y, mColor.z, mColor.w);

		mManObj->position(center.x, mY, center.y);

		for(int i = 0; i < smoothFactor; ++i)
		{
			mManObj->position(
				center.x + (cos(angle) * radius),
				mY, 
				center.y + (sin(angle) * radius));

			angle += angleChange;
		}

		mManObj->position(
			center.x + (cos(0.0f) * radius),
			mY, 
			center.y + (sin(0.0f) * radius));

		//mManObj->end();	
	}

	void QuickAndDirtyOgreDebugRenderer::DrawRectFilled( float x1, float x2, float y1, float y2 )
	{
		mManObj->begin(mMaterialString, Ogre::RenderOperation::OT_TRIANGLE_STRIP);
		mManObj->colour(mColor.x, mColor.y, mColor.z, mColor.w);

		mManObj->position(x1, mY, y1);
		mManObj->position(x2, mY, y1);
		mManObj->position(x1, mY, y2);
		mManObj->position(x1, mY, y1);

		mManObj->end();
	}

	void QuickAndDirtyOgreDebugRenderer::DrawTriangle( const XF::Vector2 &p1, const XF::Vector2 &p2, const XF::Vector2 &p3 )
	{

		mManObj->position(p1.x, mY, p1.y);
		mManObj->position(p2.x, mY, p2.y);

		mManObj->position(p2.x, mY, p2.y);
		mManObj->position(p3.x, mY, p3.y);

		mManObj->position(p3.x, mY, p3.y);
		mManObj->position(p1.x, mY, p1.y);
		mColourAllowdToChange = true;
	}

	void QuickAndDirtyOgreDebugRenderer::DrawTriangleFilled( const XF::Vector2 &p1, const XF::Vector2 &p2, const XF::Vector2 &p3 )
	{
		mManObj->begin(mMaterialString, Ogre::RenderOperation::OT_TRIANGLE_LIST);
		mManObj->colour(mColor.x, mColor.y, mColor.z, mColor.w);

		mManObj->position(p1.x, mY, p1.y);
		mManObj->position(p2.x, mY, p2.y);
		mManObj->position(p3.x, mY, p3.y);

		mManObj->end();
	}
}
